Taller Python & Audio

!pip install googletrans 
Requirement already satisfied: googletrans in /usr/local/lib/python3.6/dist-packages (3.0.0)
Requirement already satisfied: httpx==0.13.3 in /usr/local/lib/python3.6/dist-packages (from googletrans) (0.13.3)
Requirement already satisfied: certifi in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (2020.6.20)
Requirement already satisfied: chardet==3.* in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (3.0.4)
Requirement already satisfied: rfc3986<2,>=1.3 in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (1.4.0)
Requirement already satisfied: httpcore==0.9.* in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (0.9.1)
Requirement already satisfied: hstspreload in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (2020.10.6)
Requirement already satisfied: sniffio in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (1.2.0)
Requirement already satisfied: idna==2.* in /usr/local/lib/python3.6/dist-packages (from httpx==0.13.3->googletrans) (2.10)
Requirement already satisfied: h2==3.* in /usr/local/lib/python3.6/dist-packages (from httpcore==0.9.*->httpx==0.13.3->googletrans) (3.2.0)
Requirement already satisfied: h11<0.10,>=0.8 in /usr/local/lib/python3.6/dist-packages (from httpcore==0.9.*->httpx==0.13.3->googletrans) (0.9.0)
Requirement already satisfied: contextvars>=2.1; python_version < "3.7" in /usr/local/lib/python3.6/dist-packages (from sniffio->httpx==0.13.3->googletrans) (2.4)
Requirement already satisfied: hyperframe<6,>=5.2.0 in /usr/local/lib/python3.6/dist-packages (from h2==3.*->httpcore==0.9.*->httpx==0.13.3->googletrans) (5.2.0)
Requirement already satisfied: hpack<4,>=3.0 in /usr/local/lib/python3.6/dist-packages (from h2==3.*->httpcore==0.9.*->httpx==0.13.3->googletrans) (3.0.0)
Requirement already satisfied: immutables>=0.9 in /usr/local/lib/python3.6/dist-packages (from contextvars>=2.1; python_version < "3.7"->sniffio->httpx==0.13.3->googletrans) (0.14)
  1. Python. Porqué es el mejor lenguaje.

    • Python, el intérprete. Notebooks, jupyter, Collaboratory.

  2. Numpy y scipy:

    • Presentando librerías

  3. El sonido.

    • Señal de audio. El audio digital y el sonido en el mundo físico.

  4. Gráficos librería Matplotlib:

    • Ploteo básico, ploteo de señales

  5. Operaciones:

    • Señales más allá del seno. Suma de señales

  6. Dominio de frecuencias

    • Fourier

  7. Filtros

  8. Otras aplicaciones

print('Hola a todos')
Hola a todos
def esc(code):
     return f'\033[{code}m'

print(esc('36;1;4') + 'Bievenidos al taller introductorio de python aplicado al audio')
Bievenidos al taller introductorio de python aplicado al audio

Por qué python es el mejor lenguaje?

  • Batteries included Rich collection of already existing bricks of classic numerical methods, plotting or data processing tools. We don’t want to re-program the plotting of a curve, a Fourier transform or a fitting algorithm. Don’t reinvent the wheel!

  • Easy to learn Most scientists are not payed as programmers, neither have they been trained so. They need to be able to draw a curve, smooth a signal, do a Fourier transform in a few minutes.

  • Easy communication To keep code alive within a lab or a company it should be as readable as a book by collaborators, students, or maybe customers. Python syntax is simple, avoiding strange symbols or lengthy routine specifications that would divert the reader from mathematical or scientific understanding of the code.

  • Efficient code Python numerical modules are computationally efficient. But needless to say that a very fast code becomes useless if too much time is spent writing it. Python aims for quick development times and quick execution times.

  • Universal Python is a language used for many different problems. Learning Python avoids learning a new software for each new problem.

Fuente

from googletrans import Translator 
texto_en_ingles = """Batteries included Rich collection of already existing bricks of classic numerical methods, plotting or data processing tools. We don’t want to re-program the plotting of a curve, a Fourier transform or a fitting algorithm. Don’t reinvent the wheel!
Easy to learn Most scientists are not payed as programmers, neither have they been trained so. They need to be able to draw a curve, smooth a signal, do a Fourier transform in a few minutes.
Easy communication To keep code alive within a lab or a company it should be as readable as a book by collaborators, students, or maybe customers. Python syntax is simple, avoiding strange symbols or lengthy routine specifications that would divert the reader from mathematical or scientific understanding of the code.
Efficient code Python numerical modules are computationally efficient. But needless to say that a very fast code becomes useless if too much time is spent writing it. Python aims for quick development times and quick execution times.
Universal Python is a language used for many different problems. Learning Python avoids learning a new software for each new problem."""
translate = Translator()
texto_en_español = translate.translate(texto_en_ingles, dest='es', source = 'en')
for oracion in texto_en_español.text.split('\n'):
    print('-.-')
    print(oracion)
-.-
Pilas incluidas Amplia colección de ladrillos ya existentes de métodos numéricos clásicos, herramientas de trazado o procesamiento de datos. No queremos reprogramar el trazado de una curva, una transformada de Fourier o un algoritmo de ajuste. ¡No reinventes la rueda!
-.-
Fácil de aprender A la mayoría de los científicos no se les paga como programadores, ni tampoco se les ha formado para ello. Necesitan poder dibujar una curva, suavizar una señal, hacer una transformada de Fourier en unos minutos.
-.-
Comunicación sencilla Para mantener vivo el código dentro de un laboratorio o una empresa, los colaboradores, estudiantes o quizás los clientes deben poder leerlo como un libro. La sintaxis de Python es simple, evitando símbolos extraños o especificaciones de rutina largas que desviarían al lector de la comprensión matemática o científica del código.
-.-
Los módulos numéricos de código eficiente de Python son computacionalmente eficientes. Pero no hace falta decir que un código muy rápido se vuelve inútil si se dedica demasiado tiempo a escribirlo. Python apunta a tiempos de desarrollo rápidos y tiempos de ejecución rápidos.
-.-
Universal Python es un lenguaje que se usa para muchos problemas diferentes. Aprender Python evita aprender un nuevo software para cada nuevo problema.

Tipos de variables

# esto 


string = "hola"


#los comentarios sirven para ir explicando el codigo
#integer
# numero = 2 
# #float 
# numero_con_coma = 2.5 
# #el booleano puede ser True or False
# #boolean 
# booleano = True
string
("asdjugeudoser asderusrosg oweousfouhet ijdoiwaw.'';'5'345;345';34'",
 'juicio')
#algunos operadores 

Estructura de datos

Listas, set, tuplas y diccionario

#podemos guardar los datos en listas 
lista = ['a', 'b', 1, 3]
#podemos usar otros tipos de datos como 
tupla = ('a', 1)
lista_de_tuplas = [('juan', 10), ('María', 18)] 
triplet = ('a', 4, 5)
etc = (1, 2, 3, 4, 5, 6)
#diccionarios 
diccionario = {'k' : 34}
diccionario.keys(), diccionario.values()
(dict_keys(['k']), dict_values([34]))
asd = {2 : 'asdasd'} 
asd.keys()
dict_keys([2])

Indexing

Extraer elementos de estructura de datos

Si quisiera guardar los datos de todos mis alumnos utilizo una lista de tuplas:

Slicing

lista_n = [1,2,3,4,5,6,7,8,9]
# start:stop:step
# start::step 
# start:stop 
# start :: 
# :: end
lista_n[1:6:2]
[2, 4, 6]

Funciones

# Escribir una función que recibe la longitud del lado de un cuadrado y retorna el área del cuadrado
def areaSquare(lado): 
    return lado ** 2
# Escribir una función que recibe el largo, ancho y profundidad de un ”cuboide” y retorna el área de la superficie del ”cuboide”
def surfaceAreaCuboid(largo,ancho,profundidad): 
    superficie = 2 * (largo * ancho + largo * profundidad + ancho * profundidad)
    return superficie

Ahora llamamos a las funciones definidas anteriormente

areaSquare(3)
9
surfaceAreaCuboid(1,3,5)
46

Numpy & Scipy

Funciones para hacer y trabajar audio. Ambientes científicos.

An introduction to Numpy and Scipy

import numpy as np
from scipy import signal
array = np.array([[1,2,3,4,5],[1,2,3,4,4]])
array.shape
(2, 5)
x = np.array([1., -1., -2., 3])
x[x < 0] += 20
x
array([ 1., 19., 18.,  3.])

El sonido.

El sonido en la física. El sonido en una computadora. Cómo se traduce una función continua e infinitamente densa.

\(y=A * sin({2\pi f t})\)

  • f = frecuencia

  • t = tiempo

\(w = 2*\pi*f\)

  • A = 1

\(y=sin({w*t})\)

El sonido digital

Cómo interpreta una computadora el sonido?

  • sampling

  • cuantización

![qXPKTyAPOCOcMQS6snKBBwcdAt62-dk6x3uxh.jpeg](data:image/jpeg;base64,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)

#Para reproducir audio en la Jupyter N.
from IPython.display import Audio, display
#cantidad de puntos por segundo 
framerate = 44100
#cinco segundos de audio 
t = np.linspace(0,5,framerate*5)
f = 440
data = np.sin(2*np.pi*f*t)
data
array([ 0.00000000e+00,  6.26486079e-02,  1.25051088e-01, ...,
       -1.25051088e-01, -6.26486079e-02, -1.40940660e-13])
def simple_wave(f, t, framerate, A = 1):
    '''Funcion para crear una onda senoidal
        inputs:
        f = frecuencia, int 
        t = tiempo, int 
        A = amplitud, int
        return:
        wave = onda senoidal, np.array
    '''
    t = np.linspace(0, t, framerate*t)
    return np.sin(2*np.pi*f*t)
la440 = simple_wave(440, 5, 44100)
Audio(data=la440, rate=44100)

Distancia entre notas occidentales: intervalos de media nota.

\(y=n_{0}*2^\frac{n}{12}\)

#Escala musical 
n_0 = 440
notas = [440*2**(n/12) for n in range(0, 13)]
#función senoidal para cada nota
funciones_nota = [] 
for note_frequency in notas: 
     funciones_nota.append(simple_wave(note_frequency, 2, 44100))
#encontrar notas de la escala pentatónica mayor de c 
# la, La#, si, do, do#, re, re#, mi, fa, fa#, sol, sol#, la
index_notas = [0,4,5,7,11,12]
scala_pentatonica = [funciones_nota[i] for i in index_notas]
Audio(data=scala_pentatonica[1], rate = 44100)
#juntamos las notas de la pentatónica
audio_concatenado = np.concatenate(scala_pentatonica)
Audio(audio_concatenado, rate=44100)

Gráficos: Librería Matplotlib

#Para plotear
import matplotlib.pyplot as plt
plt.style.use('seaborn-darkgrid')
%matplotlib inline
# plt.figure(figsize=(5,5))
# y = audio_concatenado
# t = np.linspace(0, 2*5, 44100*2*5)
# plt.xlim(0, 0.005)
# plt.plot(t, y)
# plt.grid()
# plt.xlabel('tiempo')
# plt.ylabel('amplitud')
# plt.show()

Operaciones entre señales

Más alla de las funciones trigonométricas. Operaciones entre señales.

#señal triangular 
t = np.linspace(0, 1, 44100)
#2*pi*f*t 
plt.xlim([0, 0.005])
triangle = signal.sawtooth(2 * np.pi * 800 * t, 0.5)
plt.plot(t, triangle)
[<matplotlib.lines.Line2D at 0x7f7175bf6e80>]
../_images/Audio_II_61_1.png
t = np.linspace(0, 1, 500, endpoint=False)
square = signal.square(2 * np.pi * 5 * t)
plt.plot(t, square)
plt.ylim(-2, 2)
(-2.0, 2.0)
../_images/Audio_II_62_1.png
t = np.linspace(0, 5, 44100*5)
w = signal.chirp(t, f0=1, f1=1500, t1=5, method='quadratic' )
plt.plot(t, w)
plt.xlim([0, 2])
plt.xlabel('t (sec)')
plt.show()
../_images/Audio_II_63_0.png
Audio(w, rate=44100)
#Armar una señal compleja con una función seno.
def simple_cos_wave(f, t, framerate, A = 1):
    '''Funcion para crear una onda cos
        inputs:
        f = frecuencia, int 
        t = tiempo, int 
        A = amplitud, int
        return:
        wave = onda senoidal, np.array
    '''
    t = np.linspace(0, t, framerate*t)
    return A*np.cos(2*np.pi*f*t)
cos_1 = simple_cos_wave(300, 5, 44100)
cos_2 = simple_cos_wave(400, 5, 44100)
sin_1 = simple_wave(500, 5, 44100)
sin_2 = simple_wave(200, 5, 44100)
suma_de_señales = cos_1 + cos_2 + sin_1 + sin_2 
plt.figure()
t = np.linspace(0, 5, 44100*5)
plt.plot(t, suma_de_señales)
plt.xlim([0, 0.05])
plt.grid()
plt.show()
../_images/Audio_II_67_0.png
Audio(suma_de_señales, rate=44100)

Generando ruido

#distribución gauseana
mean = 0
std = 1 
framerate = 44100
seconds = 5
num_samples = seconds*framerate
noise = np.random.normal(mean, std, size=num_samples)
x = np.linspace(0, seconds, num_samples)
plt.plot(x, noise)
plt.show()
../_images/Audio_II_70_0.png
Audio(0.5*noise, rate=framerate)
sin_noise = sin_1 + noise 
Audio(sin_noise, rate = framerate)

Dominio de frecuencias

Fourier. análisis frecuenciar

from scipy.fft import fft, fftshift
def fourier_calculation(y, framerate):
    '''Aplicando fast fourier transform'''
    yf = fft(y)
    N = len(y)
    yf = 2.0/N *np.abs(yf[0:N//2])
    xf = np.linspace(0.0, 1/2*framerate, N//2)
    return yf, xf
yf, xf = fourier_calculation(w, framerate = 44100)
plt.xlim([0, 1000])
plt.plot(xf, yf)
[<matplotlib.lines.Line2D at 0x7f7174f68be0>]
../_images/Audio_II_77_1.png
yf, xf = fourier_calculation(suma_de_señales, framerate = 44100)
plt.plot(xf, yf)
plt.xlim([0, 1000])
(0.0, 1000.0)
../_images/Audio_II_78_1.png

Espectograma

a = plt.specgram(w, Fs=44100, cmap='jet')
plt.ylim([0,3000])
plt.colorbar()
plt.show()
../_images/Audio_II_80_0.png
f, t, Sxx = signal.spectrogram(w, fs=44100, nperseg=256*2, nfft=512*2)
plt.pcolormesh(t, f, Sxx, shading='gouraud', cmap='jet_r')
plt.ylim([0,2000])
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()
../_images/Audio_II_81_0.png
f, t, Sxx = signal.spectrogram(suma_de_señales,  44100, nperseg=256*2, nfft=512*2)
plt.pcolormesh(t, f, Sxx, shading='gouraud')
plt.ylim([0,800])
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()
../_images/Audio_II_82_0.png
def plot_multiple(y, fs = 44100, plot_type = 'plotly'):
    '''Plotea primero la onda en dominio de tiempo, luego el espectro (FFT) y luego el espectrograma'''
    
    #Creo el espacio para plotear, una "figura" vacia
    plt.figure(figsize=(15,15))
    x = np.linspace(0, len(y)/fs, len(y))
    #Dividido en 3 filas y 1 columna, ploteo la onda en el 1er espacio
    plt.subplot(3, 1, 1)
    #plt.xlim([0, 0.005])
    plt.plot(x, y)
    #Pongo titulo al eje y
    plt.ylabel('Amplitude')
    #Grilla de fondo
    plt.grid()
    
    #FFT
    #n = len(w) = duración * framerate
    yf, xf = fourier_calculation(y, fs)
    #Plot FFT
    plt.subplot(3, 1, 2)
    #Ploteo las frecuencias positivas y sus valores, con un color RGBA
    plt.xlabel('Freq (Hz)')  
    plt.ylabel('|Y(freq)|')
    plt.xlim([0,2000])
    plt.plot(xf, yf)
    

    #plot spectogram
    if plot_type == 'scipy':
        plt.subplot(3, 1, 3)
        f, t, Sxx = signal.spectrogram(y, fs, scaling='density')
        plt.pcolormesh(t, f, Sxx, shading='gouraud', cmap='jet_r')
        #plt.specgram(y, Fs =fs)
        plt.ylabel('Frequency [Hz]')
        plt.xlabel('Time [sec]')
        plt.ylim([0,2000])
        plt.show()
    else: 
        plt.subplot(3, 1, 3)
        a = plt.specgram(y, Fs=fs, cmap='jet')
        plt.ylim([0,3000])
        plt.ylabel('Frequency [Hz]')
        plt.xlabel('Time [sec]')
        plt.colorbar()
        plt.show()
plot_multiple(w)
../_images/Audio_II_84_0.png

Practicando con grabaciones reales

from scipy.io import wavfile
import scipy.io
# samplerate, data = wavfile.read('/content/export.wav')
# print(f"number of channels = {data.shape[1]}")

# length = data.shape[0] / samplerate
# print(f"length = {length}s")
#stereo to mono
# data = data.sum(axis=1) / 2
# plot_multiple(data, samplerate)
# from scipy.signal import savgol_filter
# yhat = savgol_filter(y, 51, 3)

#Filtrado Filtrado a través de Fourier

import numpy as np
import scipy.fftpack
plt.subplots(4, 1, figsize=(10, 10))
N = 22050
secs = 1
f = 200
x = np.linspace(0,secs, N*secs)
y = np.sin(2*np.pi*f*x) + np.random.random(N*secs) * 0.4
plt.subplot(4,1,1)
plt.plot(x[0:200],y[0:200])

w = scipy.fftpack.rfft(y)
f = scipy.fftpack.rfftfreq(N*secs, x[1]-x[0])
spectrum = w**2
plt.subplot(4,1,2)
plt.plot(f[0:1000], spectrum[0:1000])

cutoff_idx = spectrum < (spectrum.max()/5)
w2 = w.copy()
w2[cutoff_idx] = 0
spectrum2 = w2**2
plt.subplot(4,1,3)
plt.plot(f[0:1000], spectrum2[0:1000])

y2 = scipy.fftpack.irfft(w2)
plt.subplot(4,1,4)
plt.plot(x[0:200], y2[0:200])
[<matplotlib.lines.Line2D at 0x7f71767c40b8>]
../_images/Audio_II_92_1.png